官方說明文件:https://sinotrade.github.io/tutor/advanced/nonblock/
一般我們執行的function都是屬於Blocking,也就是要等到function執行結束並return執行結果,程式才會繼續往下執行,而Non-blocking Mode就是在call function時,不等function完全執行結束,就直接往下執行。
import shioaji as sj
from shioaji.constant import Action, StockPriceType, FuturesOrderType, FuturesOCType
api = sj.Shioaji(simulation=True)
api.login(
person_id='PAPIUSER06',
passwd='2222'
)
contract = api.Contracts.Futures.MXF['MXF202110']
order = api.Order(action=Action.Buy,
price=16700,
quantity=1,
price_type=StockPriceType.LMT,
order_type=FuturesOrderType.ROD,
octype=FuturesOCType.Auto,
account=api.futopt_account
)
trade = api.place_order(contract, order, timeout=0) #timeout=0,即使用Non-blocking Mode執行
print(trade)
api.logout()
執行結果如下
contract=Future(code='MXFJ1', symbol='MXF202110', name='小型臺指10', category='MXF', delivery_month='202110', delivery_date='2021/10/20', underlying_kind='I', unit=1, limit_up=17998.0, limit_down=14726.0, reference=16362.0, update_date='2021/10/07') order=Order(action=<Action.Buy: 'Buy'>, price=16700, quantity=1, account=FutureAccount(person_id='PAPIUSER06', broker_id='F002000', account_id='9102620', signed=True, username='PAPIUSER06'), price_type=<StockPriceType.LMT: 'LMT'>, order_type=<FuturesOrderType.ROD: 'ROD'>) status=OrderStatus(status=<Status.Inactive: 'Inactive'>)
可以看到trade的資訊中並沒有委託單號,且OrderStatus為Status.Inactive,因為在Non-blocking Mode下並不會等到place_order完全執行結束後才往下執行,而是不等function回傳完整的結果,就直接往下執行下面的程式。在Non-blocking Mode下執行place_order,若要取得委託單完整資訊,可以透過callback方式回傳並取得。
在Non-blocking Mode下,callback方式有兩種,一種是order callback,可參考Day 15 - Order & Deal Event中的說明,而另一個是Non-blocking place order callback
order callback跟Non-blocking place order callback的不同點在於,order callback在宣告完後,呼叫api.set_order_callback將callback程式指定為自行定義的callback function;而Non-blocking place order callback則是在呼叫api.place_order時,傳入自行定義的callback function,且此參數只有在Non-blocking Mode才有作用
程式範例說明如下:
import shioaji as sj
from shioaji.constant import Action, StockPriceType, FuturesOrderType, FuturesOCType
from shioaji.order import Trade #匯入Trade物件
import threading #匯入threading模組
api = sj.Shioaji(simulation=True)
api.login(
person_id='PAPIUSER06',
passwd='2222'
)
event = threading.Event() #建立一個Event
def non_blocking_cb(trade:Trade):
print('__non_blocking_callback__')
print(trade) #將trade資訊輸出
event.set() #執行set()讓主程式繼續執行
contract = api.Contracts.Futures.MXF['MXF202110']
order = api.Order(action=Action.Buy,
price=16700,
quantity=1,
price_type=StockPriceType.LMT,
order_type=FuturesOrderType.ROD,
octype=FuturesOCType.Auto,
account=api.futopt_account
)
trade = api.place_order(contract, order, timeout=0, cb=non_blocking_cb) #傳入上面定義的callback function
print(trade)
print('wait for callback...')
event.wait() #讓主程式進入等待而不直接結束
api.logout()
為了讓程式執行後,等待Non-blocking place order callback執行後才結束程式,在這裡我們透過Event().wait()來進行等待,並當callback function執行時,呼叫Event().set()讓原本的程式繼續執行。
最後,比較一下Blocking & Non-blocking Mode執行時間上的差異,請注意,這個執行時間會受到網路通訊品質及交易時段影響,以下時間僅供參考。
測試的程式內容如下:
import shioaji as sj
from shioaji.constant import Action, StockPriceType, FuturesOrderType, FuturesOCType
from shioaji.order import Trade
import threading, time
api = sj.Shioaji(simulation=True)
api.login(
person_id='PAPIUSER06',
passwd='2222'
)
contract = api.Contracts.Futures.MXF['MXF202110']
order = api.Order(action=Action.Buy,
price=16750,
quantity=1,
price_type=StockPriceType.LMT,
order_type=FuturesOrderType.ROD,
octype=FuturesOCType.Auto,
account=api.futopt_account
)
event = threading.Event()
def non_blocking_cb(trade:Trade):
print('__non_blocking_callback__')
# print(trade)
event.set()
print('start place_order with non-blocking...')
start_time = time.time() #抓取non-blocking開始時間
def non_blocking_cb(trade:Trade):
print('__non_blocking_callback__')
# print(trade) #因測試執行時間,所以不做輸出動作
print(f'time of non blocking callback:{time.time()-start_time}') #callback執行時,計算所要花費的時間
event.set()
trade = api.place_order(contract, order, timeout=0, cb=non_blocking_cb)
# print(trade) #因測試執行時間,所以不做輸出動作
print(f'time after place_order:{time.time()-start_time}') #計算api.place_order回傳結果所花費的時間
print('wait for non blocking callback...')
event.wait()
print('start place_order with blocking...')
start_time = time.time() #抓取blocking開始時間
def blocking_cb(stat, msg):
print('__blocking_callback__')
# print(stat, msg) #因測試執行時間,所以不做輸出動作
print(f'time of blocking callback:{time.time()-start_time}') #callback執行時,計算所要花費的時間
event.set()
api.set_order_callback(blocking_cb)
trade = api.place_order(contract, order)
# print(trade) #因測試執行時間,所以不做輸出動作
print(f'time after place_order:{time.time()-start_time}') #計算api.place_order回傳結果所花費的時間
print('wait for blocking callback...')
api.logout()
執行結果如下:
Response Code: 0 | Event Code: 0 | Info: host '218.32.76.102:80', hostname '218.32.76.102:80' IP 218.32.76.102:80 (host 1 of 1) (host connection attempt 1 of 1) (total connection attempt 1 of 1) | Event: Session up
start place_order with non-blocking...
time after place_order:0.015607357025146484
wait for non blocking callback...
__non_blocking_callback__
time of non blocking callback:3.3490772247314453
OrderState.FOrder {'operation': {'op_type': 'New', 'op_code': '00', 'op_msg': ''}, 'order': {'id': 'b0cb8b7d', 'seqno': '980069', 'ordno': 'kY01c', 'account': {'account_type': 'F', 'person_id': '', 'broker_id': 'F002000', 'account_id': '9102620', 'signed': True}, 'action': 'Buy', 'price': 16750.0, 'quantity': 1, 'order_type': 'ROD', 'market_type': 'Night', 'oc_type': 'New', 'subaccount': ''}, 'status': {'id': 'b0cb8b7d', 'exchange_ts': 1633621393, 'modified_price': 0.0, 'cancel_quantity': 0, 'order_quantity': 1}, 'contract': {'security_type': 'FUT', 'code': 'MXF', 'exchange': 'TIM', 'delivery_month': '202110', 'delivery_date': '', 'strike_price': 0.0, 'option_right': 'Future'}}
start place_order with blocking...
OrderState.FOrder {'operation': {'op_type': 'Cancel', 'op_code': '00', 'op_msg': '超過動態價格穩定標準'}, 'order': {'id': 'b0cb8b7d', 'seqno': '980069', 'ordno': 'kY01c', 'account': {'account_type': 'F', 'person_id': '', 'broker_id': 'F002000', 'account_id': '9102620', 'signed': True}, 'action': 'Buy', 'price': 16750.0, 'quantity': 1, 'order_type': 'ROD', 'market_type': 'Day', 'oc_type': 'New', 'subaccount': ''}, 'status': {'id': 'b0cb8b7d', 'exchange_ts': 1633621394, 'modified_price': 0.0, 'cancel_quantity': 1, 'order_quantity': 1}, 'contract': {'security_type': 'FUT', 'code': 'MXF', 'exchange': 'TIM', 'delivery_month': '202110', 'delivery_date': '', 'strike_price': 0.0, 'option_right': 'Future'}}
__blocking_callback__
time of blocking callback:0.0009984970092773438
__blocking_callback__
time of blocking callback:0.0019960403442382812
__blocking_callback__
time of blocking callback:0.0019960403442382812
__blocking_callback__
time of blocking callback:0.0029954910278320312
time after place_order:0.05179405212402344
wait for blocking callback...
從執行結果中,可以看到在non-blocking mode下,place_order會先回傳trade資訊,之後才會執行callback;但是在blocking mode下,是先會執行callback,然後place_order才會回傳trade資訊。
時間差異比較如下:
time.time()-start_time | blocking | non-blocking |
---|---|---|
place_order | 0.05179405212402344 | 0.015607357025146484 |
callback | 0.0029954910278320312 | 3.3490772247314453 |
而以下所列出的function,都支援以non-blocking mode的方式執行: |